#include <QtGui>
#include <QSettings>
#include <Phonon/AudioOutput>
#include <QDesktopServices>
#include <QUrl>
#include <QSplitter>

#include "version.h"

#include "mainwindow.h"
#include "reminderdialog.h"
#include "ui_mainwindow.h"
#include "reminderitem.h"
#include "postponedialog.h"
#include "remindersettings.h"

//#include "logger.h"

#ifdef Q_OS_WIN

#include <windows.h>

#endif



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(exitApplication()));
    connect(ui->actionNew, SIGNAL(triggered()), this, SLOT(addReminder()));
    connect(ui->actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    connect(ui->actionEdit, SIGNAL(triggered()), this, SLOT(editReminder()));
    connect(ui->actionMultiply, SIGNAL(triggered()), this, SLOT(multiplyReminder()));
    connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(aboutMindReminder()));
    connect(ui->actionDelete, SIGNAL(triggered()), this, SLOT(deleteReminder()));
    connect(ui->actionSettings, SIGNAL(triggered()), this, SLOT(editSettings()));
    connect(ui->actionTest, SIGNAL(triggered()), this, SLOT(testReminder()));

    dlg = 0;
    current = 0;
    timeout = new QTimer(this);
    timeout->setInterval(1000);

    //logger = new Logger();
    this->setSystemTrayIcon();
    this->readSettings();
    this->applySettings();

    ui->tools_groupBox->setDisabled(true);


    model = new QStandardItemModel(ui->listView);
    ui->listView->setModel(model);

    ui->listView->addAction(ui->actionNew);
    ui->listView->addAction(ui->actionEdit);
    ui->listView->addAction(ui->actionMultiply);
    ui->listView->addAction(ui->actionTest);
    ui->listView->addAction(ui->actionDelete);

    ui->listView->setContextMenuPolicy(Qt::ActionsContextMenu);

    ui->splitter->setStretchFactor(ui->splitter->indexOf(ui->listView), 1);
    ui->splitter->setStretchFactor(ui->splitter->indexOf(ui->calendarWidget), 0);

    connect(ui->listView, SIGNAL(activated(QModelIndex)), this, SLOT(itemEdit(QModelIndex)));
    connect(ui->listView, SIGNAL(clicked(QModelIndex)), this, SLOT(itemActivated(QModelIndex)));

    connect(ui->calendarWidget, SIGNAL(activated(QDate)), this, SLOT(addReminder(QDate)));

    connect(ui->tools_toolButton, SIGNAL(clicked()), this, SLOT(toggleReminder()));

    connect(timeout, SIGNAL(timeout()), this, SLOT(showTimeout()));

    this->loadFromSettings();

    if (loadUpdatePlugin()){
        connect(updmgr->updmgrObject(), SIGNAL(blockUserInput(bool)), this, SLOT(setDisabled(bool)));
        updmgr->checkForUpdate("mind reminder",_STR_PRODUCT_VERSION);
    }
}

MainWindow::~MainWindow()
{
    this->saveSettings();
    delete ui;
}

void MainWindow::multiplyReminder()
{
    if(!current) return;
    if(!dlg){
        dlg = new ReminderDialog(this);
        connect(dlg, SIGNAL(playSound(QString)), this, SLOT(playSound(QString)));
        connect(dlg, SIGNAL(stopSound()), media, SLOT(stop()));
        connect(media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
            dlg, SLOT(mediaState(Phonon::State,Phonon::State)));
        connect(dlg, SIGNAL(accepted()), this, SLOT(saveReminder()));
    }
    dlg->setIndex(1+this->maxIndex());
    dlg->setEdit(false);
    dlg->setDefaults();
    dlg->setReminderName(tr("Copy of %1").arg(current->getName()));
    dlg->setFromDate(current->getStart());

    dlg->setLoadUrl(current->hasUrl());
    dlg->setUrl(current->hasUrl() ? current->getUrl() : QString::null);

    dlg->setShutdown(current->getShutdown());
    if(dlg->getShutdown()){
        dlg->setShutdownTimeout(current->getShutdownTimeout());
        switch(current->getShutdownType()){
        case Reminder::LogOff: dlg->setShutdownType(0); break;
        case Reminder::TurnOff: dlg->setShutdownType(1); break;
        case Reminder::Restart: dlg->setShutdownType(2); break;
        case Reminder::Hibernate: dlg->setShutdownType(3); break;
        }
    }
    dlg->setExecute(current->getExecute());
    if(dlg->getExecute()){
        dlg->setExecutePath(current->getExecutePath());
        dlg->setExecuteArgs(current->getExecuteArgs());
    }
    dlg->setCheckMissed(current->hasCheckMissed());
    switch(current->getType()){
    case Reminder::Once: {
        dlg->setRepeat(false);
        break;
    }
    case Reminder::Minutely: {
        dlg->setIntervalIdx(0);
        dlg->setMinutes(current->getMinutes());
        break;
    }
    case Reminder::Hourly: {
        dlg->setIntervalIdx(1);
        dlg->setHours(current->getHours());
        break;
    }
    case Reminder::Daily: {
        dlg->setIntervalIdx(2);
        dlg->setDays(current->getDays());
        break;
    }
    case Reminder::Monthly: {
        dlg->setIntervalIdx(3);
        break;
    }
    case Reminder::MonthlyByDay: {
        dlg->setIntervalIdx(4);
        break;
    }
    case Reminder::Yearly: {
        dlg->setIntervalIdx(5);
        break;
    }
    case Reminder::YearlyByDay: {
        dlg->setIntervalIdx(6);
    }
    case Reminder::Timeout: {
        dlg->setIntervalIdx(7);
        dlg->setTimeout(current->getTimeout());
    }
    default: break;
    }
    if(current->hasAudio()){
        dlg->setAudio(true);
        dlg->setAudioName(current->getAudioName());
    }
    else{
        dlg->setAudio(false);
    }
    if(current->hasTooltip()){
        dlg->setTip(true);
        dlg->setTipText(current->getTooltipMsg());
    }
    else{
        dlg->setTip(false);
        dlg->setTipText(QString::null);
    }
    if(current->hasDialog()){
        dlg->setDialog(true);
        dlg->setDialogText(current->getDialogMsg());
        if(current->hasAutoclose()){
            dlg->setAutoclose(true);
            dlg->setAutocloseInterval(current->getAutocloseInterval());
        }
    }
    else{
        dlg->setDialog(false);
        dlg->setDialogText(QString::null);
    }
    dlg->exec();
}

void MainWindow::toggleReminder()
{
    if(current){
        if(current->isRunned()){
            current->stop();
        }
        else {
            current->start();
            this->writeLastCall(current);
        }
    }
}

void MainWindow::itemActivated(const QModelIndex &index)
{
    if(index.isValid()){
        ReminderItem *item = static_cast<ReminderItem*>(model->itemFromIndex( index ));
        current = item->getReminder();
        ui->tools_groupBox->setDisabled(false);
        ui->toolsNextrun_dateTimeEdit->setDisabled(current->getState() == Reminder::Stopped);
        reminderState(current);
    }
}

void MainWindow::itemEdit(const QModelIndex &index)
{
    this->itemActivated(index);
    this->editReminder();
}

void MainWindow::editReminder()
{
    if(!current) return;
    if(!dlg){
        dlg = new ReminderDialog(this);
        connect(dlg, SIGNAL(playSound(QString)), this, SLOT(playSound(QString)));
        connect(dlg, SIGNAL(stopSound()), media, SLOT(stop()));
        connect(media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
            dlg, SLOT(mediaState(Phonon::State,Phonon::State)));
        connect(dlg, SIGNAL(accepted()), this, SLOT(saveReminder()));
    }
    dlg->setEdit(true);
    dlg->setDefaults();
    dlg->setReminderName(current->getName());
    dlg->setFromDate(current->getStart());

    dlg->setLoadUrl(current->hasUrl());
    dlg->setUrl(current->hasUrl() ? current->getUrl() : QString::null);

    dlg->setShutdown(current->getShutdown());
    dlg->setAutodelete(current->getAutodelete());
    if(current->getShutdown()){
        dlg->setShutdownTimeout(current->getShutdownTimeout());
        switch(current->getShutdownType()){
        case Reminder::LogOff : dlg->setShutdownType(0); break;
        case Reminder::TurnOff : dlg->setShutdownType(1); break;
        case Reminder::Restart : dlg->setShutdownType(2); break;
        case Reminder::Hibernate : dlg->setShutdownType(3); break;
        }
    }
    dlg->setExecute(current->getExecute());
    if(dlg->getExecute()){
        dlg->setExecutePath(current->getExecutePath());
        dlg->setExecuteArgs(current->getExecuteArgs());
    }
    dlg->setCheckMissed(current->hasCheckMissed());

    switch(current->getType()){
    case Reminder::Once: {
        dlg->setRepeat(false);
        break;
    }
    case Reminder::Minutely: {
        dlg->setIntervalIdx(0);
        dlg->setMinutes(current->getMinutes());
        break;
    }
    case Reminder::Hourly: {
        dlg->setIntervalIdx(1);
        dlg->setHours(current->getHours());
        break;
    }
    case Reminder::Daily: {
        dlg->setIntervalIdx(2);
        dlg->setDays(current->getDays());
        break;
    }
    case Reminder::Monthly: {
        dlg->setIntervalIdx(3);
        break;
    }
    case Reminder::MonthlyByDay: {
        dlg->setIntervalIdx(4);
        break;
    }
    case Reminder::Yearly: {
        dlg->setIntervalIdx(5);
        break;
    }
    case Reminder::YearlyByDay: {
        dlg->setIntervalIdx(6);
        break;
    }
    case Reminder::Timeout: {
        dlg->setIntervalIdx(7);
        dlg->setTimeout(current->getTimeout());
        break;
    }
    default: break;
    }
    if(current->hasAudio()){
        dlg->setAudio(true);
        dlg->setAudioName(current->getAudioName());
    }
    else{
        dlg->setAudio(false);
    }
    if(current->hasTooltip()){
        dlg->setTip(true);
        dlg->setTipText(current->getTooltipMsg());
    }
    else{
        dlg->setTip(false);
        dlg->setTipText(QString::null);
    }
    if(current->hasDialog()){
        dlg->setDialog(true);
        dlg->setDialogText(current->getDialogMsg());
        if(current->hasAutoclose()){
            dlg->setAutoclose(true);
            dlg->setAutocloseInterval(current->getAutocloseInterval());
        }
    }
    else{
        dlg->setDialog(false);
        dlg->setDialogText(QString::null);
    }
    dlg->exec();
}

void MainWindow::reminderState(Reminder* reminder)
{
    if(reminder == current){
        if(!reminder){
            ui->tools_toolButton->setIcon(QIcon(":/Icons/icons/Play.png"));
            ui->toolsNextrun_dateTimeEdit->setDisabled(true);
            ui->toolsNextrun_dateTimeEdit->setDateTime(QDateTime::currentDateTime());
            ui->actionEdit->setEnabled(false);
            ui->actionMultiply->setEnabled(false);
            ui->actionTest->setEnabled(false);
            ui->actionDelete->setEnabled(false);
            if(timeout) timeout->stop();
            ui->timeout_textLabel->setText("n/a");
            ui->last_dateTimeEdit->clear();
            return;
        }
        ui->actionEdit->setEnabled(true);
        ui->actionMultiply->setEnabled(true);
        ui->actionTest->setEnabled(true);
        ui->actionDelete->setEnabled(true);

        if(reminder->getLastCall().isValid()){
            ui->last_dateTimeEdit->show();
            ui->last_dateTimeEdit->setDisabled(false);
            ui->last_dateTimeEdit->setDateTime(reminder->getLastCall());
        }
        else{
            ui->last_dateTimeEdit->hide();
            ui->last_dateTimeEdit->setDisabled(true);
        }

        ui->toolsNextrun_dateTimeEdit->setDateTime(reminder->getNextRun());
        ui->calendarWidget->setSelectedDate(reminder->getNextRun().date());
        switch(reminder->getState()){
        case Reminder::Stopped: {
            if(timeout) timeout->stop();
            ui->timeout_textLabel->setText("n/a");
            ui->tools_toolButton->setIcon(QIcon(":/Icons/icons/Play.png"));
            ui->toolsNextrun_dateTimeEdit->setDisabled(true);
            break;
        }
        case Reminder::Postponed: {
            if(timeout) timeout->start();
        }
        case Reminder::Runned:{
            if(timeout) timeout->start();
            ui->tools_toolButton->setIcon(QIcon(":/Icons/icons/Stop.png"));
            ui->toolsNextrun_dateTimeEdit->setDisabled(false);
            break;
        }
        }
    }
    switch(reminder->getState()){
        case Reminder::Stopped:{
            //qDebug() << "Change state /STOP/ for: " << reminder->getName();
            this->writeLastCall(reminder, true);
            break;
        }
        case Reminder::Runned:{
            //qDebug() << "Change state /START/ for: " << reminder->getName();
            break;
        }
        default: break;
    }
    this->saveSettings();
}

void MainWindow::setSystemTrayIcon()
{
    if(!QSystemTrayIcon::isSystemTrayAvailable() ){
        return;
    }
    this->createTrayActions();
    this->createMultimediaObject();

    trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(muteAction);
    trayIconMenu->addAction(minimizeAction);
    trayIconMenu->addAction(restoreAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);

    trayIcon = new QSystemTrayIcon(this->windowIcon(), this);
    trayIcon->setContextMenu(trayIconMenu);

    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(systemTrayActivation(QSystemTrayIcon::ActivationReason)));
    connect(trayIcon, SIGNAL(messageClicked()), media, SLOT(stop()));

    trayIcon->show();
}

void MainWindow::createTrayActions()
{
    muteAction = new QAction(QIcon(":/Icons/icons/MuteReminder.png"), tr("M&ute"), this);
    muteAction->setCheckable(true);
    connect(muteAction, SIGNAL(triggered()), this, SLOT(mute()));

    minimizeAction = new QAction(QIcon(":/Icons/icons/MinimizeReminder.png"), tr("Mi&nimize"), this);
    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    maximizeAction = new QAction(tr("Ma&ximize"), this);
    connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));

    restoreAction = new QAction(QIcon(":/Icons/icons/RestoreReminder.png"), tr("&Restore"), this);
    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

    quitAction = new QAction(QIcon(":/Icons/icons/ShutdownReminder.png"), tr("&Quit"), this);
    connect(quitAction, SIGNAL(triggered()), this, SLOT(exitApplication()));
}

void MainWindow::createMultimediaObject()
{
    media = new Phonon::MediaObject(this);

    Phonon::AudioOutput *audioOutput =
           new Phonon::AudioOutput(Phonon::NotificationCategory, this);
    Phonon::createPath(media, audioOutput);
}

void MainWindow::aboutMindReminder()
{
    QDate c = QDate::currentDate();
    if(c.month() == 12 && c.day() >= 20 )
        this->playSound("Jinglebells.wav");
    else
        this->playSound("RainWalking.wav");
    QString msg(tr("Version: %1\nAuthor: Venelin Georgiev\nPleven, Bulgaria\nE-mail: veni_georgiev@mail.bg")
            .arg(_STR_PRODUCT_VERSION));
    QMessageBox::about( this, tr("About Mind Reeminder"), msg) ;
}

void MainWindow::systemTrayActivation(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason) {
        case QSystemTrayIcon::Trigger:
        case QSystemTrayIcon::DoubleClick:
        case QSystemTrayIcon::MiddleClick:
        {
            if(this->isMinimized()){
                this->showNormal();
                this->activateWindow();
                break;
            }
            if(this->isHidden()){
                this->show();
                this->activateWindow();
                break;
            }
            else{
                this->hide();
                break;
            }
        }
            default: return;
        }
}

bool MainWindow::hasMinimizedStartup()
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Settings");
    bool minimize = settings.value("RunMinimized", true).toBool();
    settings.endGroup();
    return minimize;
}

void MainWindow::onOtherInstanceMessage(const QString &msg)
{
    qDebug() << msg;
    if(this->isHidden()) this->show();
}

void MainWindow::remind(Reminder *reminder, bool test){
    if(!reminder) return;
    /*
    QString log = QString("New reminder event: %1 with Index: %2")
            .arg(reminder->getName())
            .arg(reminder->getIndex())
            ;
    logger->writeLog(log);
    */
    if(!test) this->checkMissedReminder(reminder);
    if(reminder->hasTooltip()){
        trayIcon->showMessage(tr("Mind Reminder"), reminder->getTooltipMsg(), QSystemTrayIcon::Information, 10000);
    }
    if(reminder->hasDialog()){
        PostponeDialog* dlg = new PostponeDialog(0);
        dlg->setWindowTitle(reminder->getName());
        dlg->setDialogMsg(reminder->getDialogMsg());
        if(reminder->hasAutoclose()){
            dlg->setAutoclose(reminder->getAutocloseInterval());
            dlg->runAutoclose();
        }
        if(reminder->getAutodelete() || test){
            dlg->disablePostpone(true);
        }
        else {
            dlg->disablePostpone(false);
            connect(dlg, SIGNAL(postpone(uint)), reminder, SLOT(postpone(uint)));
        }
        connect(dlg, SIGNAL(stopSound()), media, SLOT(stop()));
        dlg->show();
        dlg->activateWindow();
    }
    if(reminder->hasAudio()){
        this->playSound(reminder->getAudioName());
    }

    if(reminder->hasUrl()){
        QUrl url(reminder->getUrl());
        if(url.isValid()){
            QDesktopServices::openUrl(url);
        }
    }
    if(reminder->getExecute()){
        QString exe = QString("\"%1\"").arg(reminder->getExecutePath());
        if(!reminder->getExecuteArgs().isEmpty()){
            exe.append(QString(" %1").arg(reminder->getExecuteArgs()));
        }
        if(!exe.isEmpty()){
            QDir appdir = qApp->applicationDirPath();
            QFileInfo info(reminder->getExecutePath());
            QProcess *execute = new QProcess(this);
            connect(execute, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(executeLog(QProcess::ProcessState)));
            execute->setWorkingDirectory(info.absoluteDir().absolutePath());
            execute->setStandardOutputFile(appdir.filePath("MindReminder.log"), QIODevice::Append);
            execute->start(exe);
        }
    }
    if(!test){
        this->writeLastCall(reminder);
        #ifdef Q_OS_WIN
            if(reminder->getShutdown()){
                QString program = "shutdown";
                switch(reminder->getShutdownType()){
                case Reminder::LogOff:
                    program.append(QString(" /l"));
                    break;
                case Reminder::TurnOff:
                    program.append(QString(" /s /t %1").arg(reminder->getShutdownTimeout()));
                    break;
                case Reminder::Restart:
                    program.append(QString(" /r /t %1").arg(reminder->getShutdownTimeout()));
                    break;
                case Reminder::Hibernate:
                    program.append(QString(" /h"));
                    break;
                default:
                    program.append(" /p");
                    break;
                }
                QProcess *myProcess = new QProcess(this);
                myProcess->startDetached(program);
            }
        #endif
    }
    if(reminder->getAutodelete()){
        this->deleteReminder(reminder, true);
    }
}

void MainWindow::remind(Reminder* reminder)
{
    this->remind(reminder, false);
}

int MainWindow::maxIndex() const
{
    int index = 0;
    QMap<int, Reminder*>::const_iterator i = reminders.constBegin();
    while (i != reminders.constEnd()) {
        Reminder* r = i.value();
        if(index < r->getIndex()){
            index = r->getIndex();
        }
        ++i;
    }
    return index;
}

void MainWindow::addReminder()
{
    this->addReminder(QDate(0,0,0));
}

void MainWindow::addReminder(const QDate& date)
{
    if(!dlg){
        dlg = new ReminderDialog(this);
        connect(dlg, SIGNAL(playSound(QString)), this, SLOT(playSound(QString)));
        connect(dlg, SIGNAL(stopSound()), media, SLOT(stop()));
        connect(media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
            dlg, SLOT(mediaState(Phonon::State,Phonon::State)));
        connect(dlg, SIGNAL(accepted()), this, SLOT(saveReminder()));
    }
    dlg->setEdit(false);
    dlg->setIndex(1+this->maxIndex());
    dlg->setDefaults();
    if(date.isValid() && QDate::currentDate().daysTo(date) >= 0)
        dlg->setFromDate(QDateTime(date, QDateTime::currentDateTime().time()));
    dlg->exec();

}

void MainWindow::saveReminder()
{
    Reminder* r;
    if(dlg->hasEdit()){
        r = current;
        r->stop();
    }
    else{
        r = new Reminder(this, dlg->getIndex(), dlg->getReminderName());
        connect(r, SIGNAL(changeState(Reminder*)), this, SLOT(reminderState(Reminder*)));
        connect(r, SIGNAL(remind(Reminder*)), this, SLOT(remind(Reminder*)));
        connect(r, SIGNAL(stopNotify()), media, SLOT(stop()));
    }
    r->setName(dlg->getReminderName());
    r->getItem()->setText(r->getName());
    r->setLoadUrl(dlg->hasUrl());
    r->setUrl(dlg->getUrl());
    r->setShutdown(dlg->getShutdown());
    if(r->getShutdown()){
        r->setShutdownTimeout(dlg->getShutdownTimeout());
        switch(dlg->getShutdownType()){
        case 0: r->setShutdownType(Reminder::LogOff); break;
        case 1: r->setShutdownType(Reminder::TurnOff); break;
        case 2: r->setShutdownType(Reminder::Restart); break;
        case 3: r->setShutdownType(Reminder::Hibernate); break;
        }
    }
    r->setCheckMissed(dlg->getCheckMissed());
    r->setExecute(dlg->getExecute());
    if(r->getExecute()){
        r->setExecutePath(dlg->getExecutePath());
        r->setExecuteArgs(dlg->getExecuteArgs());
    }
    QDateTime dt = dlg->getFromDate();
    QTime start = dt.time();
    if(start.setHMS(start.hour(), start.minute(), start.second()));
        dt.setTime(start);
    r->setStart(dt);
    if(!dlg->getRepeat()){
        r->setType(Reminder::Once);
        r->setAutodelete(dlg->getAutodelete());
    }
    else{
        switch(dlg->getIntervalIdx()){
        case 0: { //minutely
            r->setType(Reminder::Minutely);
            r->setMinutes(dlg->getMinutes());
            break;
        }
        case 1: { //hourly
            r->setType(Reminder::Hourly);
            r->setHours(dlg->getHours());
            break;
        }
        case 2: { //daily
            r->setType(Reminder::Daily);
            bool days[7];
            dlg->getDays(days);
            r->setDays(days);
            break;
        }
        case 3: { //monthly
            r->setType(Reminder::Monthly);
            break;
        }
        case 4: { //monthly by day
            r->setType(Reminder::MonthlyByDay);
            break;
        }
        case 5: { //yearly
            r->setType(Reminder::Yearly);
            break;
        }
        case 6: { //yearly by day
            r->setType((Reminder::YearlyByDay));
            break;
        }
        case 7: { //timeout
            r->setType((Reminder::Timeout));
            r->setTimeout(dlg->getTimeout());
            break;
        }
    }
    }
    if(dlg->getTip()){
        r->setTooltipMsg(dlg->getTipText());
    }
    else{
        r->setTooltip(false);
    }
    if(dlg->getDialog()){
        r->setDialogMsg(dlg->getDialogText());
        if(dlg->getAutoclose()){
            r->setAutocloseInterval(dlg->getAutocloseInterval());
        }
        else r->setAutoclose(false);
    }
    else{
        r->setDialog(false);
    }
    if(dlg->getAudio()){
        r->setAudioName(dlg->getAudioName());
    }
    else{
        r->setAudio(false);
    }
    this->backupSettings();
    this->writeToSettings(r);
    QMap<int, Reminder*>::iterator i = reminders.find(r->getIndex());
    if(i == reminders.end()){
        reminders.insert(r->getIndex(), r);
        this->loadRemindersList();
    }
    if(!dlg->hasEdit()){
        this->writeLastCall(r, true);
    }
    r->start();
    current = r;
    ui->listView->setCurrentIndex(r->getItem()->index());
    this->reminderState(r);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (trayIcon->isVisible() && !isHidden()) {
        /*QErrorMessage* msg = QErrorMessage::qtHandler();
        msg->showMessage( tr("The program will keep running in the "
                             "system tray. To terminate the program, "
                             "choose <b>Quit</b> in the context menu "
                             "of the system tray entry."), "Systray");
                             */
        if(!qApp->property("hide_close_message").toBool()){
            QMessageBox msgBox;
            msgBox.setText(tr("The program will keep running in the "
                              "system tray. To terminate the program, "
                              "choose <b>Quit</b> in the context menu "
                              "of the system tray entry."));
            QCheckBox* show_checkBox = new QCheckBox(tr("Disable this message"), &msgBox);
            QLayout* layout = msgBox.layout();
            layout->addWidget(show_checkBox);

            msgBox.exec();

            QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
            QDir appdir(registry.value("IniPath", QDir::homePath()).toString());

            //QDir appdir = qApp->applicationDirPath();
            QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
            settings.beginGroup("Settings");
            {
                settings.setValue("HideCloseMessage", show_checkBox->isChecked());
            }
            settings.endGroup();

            qApp->setProperty("hide_close_message", show_checkBox->isChecked());
        }

        this->hide();
        event->ignore();
    }
    else{
        event->accept();
    }
}

void MainWindow::playSound(const QString &filename)
{
    if(this->hasMuted()){
         trayIcon->showMessage(tr("Mind Reminder"), tr("The sound state is muted!"), QSystemTrayIcon::Information, 5000);
    }
    else{
        media->setCurrentSource(Phonon::MediaSource(":/Sounds/sounds/"+filename));
        media->play();
    }
}

void MainWindow::loadRemindersList()
{
    QMapIterator<int, Reminder*> i(reminders);
    while (i.hasNext()) {
        i.next();
        if(!model->indexFromItem(i.value()->getItem()).isValid()){
            model->appendRow(i.value()->getItem());
        }
     }
}

void MainWindow::readSettings()
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Settings");
    {
        qApp->setProperty("use_secconds", settings.value("UseSecconds", false).toBool());
        qApp->setProperty("check_missed", settings.value("CheckMissed", false).toBool());
        qApp->setProperty("hide_close_message", settings.value("HideCloseMessage", false).toBool());
        this->restoreGeometry(settings.value("geometry").toByteArray());
        ui->splitter->restoreState(settings.value("splitterSizes").toByteArray());
    }
    settings.endGroup();
}

void MainWindow::loadFromSettings()
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Reminders");
    QStringList rs = settings.childGroups();
    for (int i = 0; i < rs.size(); ++i){
        bool ok;
        int n = rs.at(i).toInt(&ok);
        if(ok){
            settings.beginGroup(QString::number(n));

            Reminder* r = new Reminder(this, n, settings.value("Name", tr("New Reminder")).toString());

            connect(r, SIGNAL(changeState(Reminder*)), this, SLOT(reminderState(Reminder*)));
            connect(r, SIGNAL(remind(Reminder*)), this, SLOT(remind(Reminder*)));
            connect(r, SIGNAL(stopNotify()), media, SLOT(stop()));

            r->setStart(settings.value("Start").toDateTime());
            QString type = settings.value("Type", "Once").toString();
            if(type == "Once"){
                r->setType(Reminder::Once);
                r->setAutodelete(settings.value("Autodelete", false).toBool());
            }
            else if(type == "Minutely"){
                r->setType(Reminder::Minutely);
                r->setMinutes(settings.value("Minutes", 60).toInt());
            }
            else if(type == "Hourly"){
                r->setType(Reminder::Hourly);
                r->setHours(settings.value("Hours", 1).toInt());
            }
            else if(type == "Daily"){
                r->setType(Reminder::Daily);
                bool days[7];
                settings.beginReadArray("Days");
                for(int i = 0; i < 7; ++i) {
                     settings.setArrayIndex(i);
                     days[i] = settings.value("day", true).toBool();
                }
                settings.endArray();
                r->setDays(days);
            }
            else if(type == "Monthly"){
                r->setType(Reminder::Monthly);
            }
            else if(type == "MonthlyByDay"){
                r->setType(Reminder::MonthlyByDay);
            }
            else if(type == "Yearly"){
                r->setType(Reminder::Yearly);
            }
            else if(type == "YearlyByDay"){
                r->setType(Reminder::YearlyByDay);
            }
            else if(type == "Timeout"){
                r->setType(Reminder::Timeout);
                r->setTimeout(settings.value("Timeout", 15).toInt());
            }
            r->setAudio(settings.value("Audio", false).toBool());
            if(r->hasAudio()){
                r->setAudioName(settings.value("AudioName", "Bell.wav").toString());
            }
            r->setTooltip(settings.value("Tooltip", false).toBool());
            if(r->hasTooltip()){
                r->setTooltipMsg(settings.value("TooltipMessage", "Reminder").toString());
            }
            r->setDialog(settings.value("Dialog", false).toBool());
            if(r->hasDialog()){
                r->setDialogMsg(settings.value("DialogMessage", "Reminder").toString());
                r->setAutoclose(settings.value("DialogAutoclose", false).toBool());
                if(r->hasAutoclose()){
                    r->setAutocloseInterval(settings.value("DialogAutocloseInterval", 30).toInt());
                }
            }
            r->setLoadUrl(settings.value("LoadUrl", false).toBool());
            if(r->hasUrl()){
                r->setUrl(settings.value("Url", "www.google.com").toString());
            }
            r->setShutdown(settings.value("Shutdown", false).toBool());
            if(r->getShutdown()){
                r->setShutdownTimeout(settings.value("ShutdownTimeout", 30).toInt());
                QString sh_type = settings.value("ShutdownType", "LogOff").toString();
                if(sh_type == "LogOff") r->setShutdownType(Reminder::LogOff);
                else if(sh_type == "TurnOff") r->setShutdownType(Reminder::TurnOff);
                else if(sh_type == "Restart") r->setShutdownType(Reminder::Restart);
                else r->setShutdownType(Reminder::Hibernate);
            }
            r->setExecute(settings.value("Execute", false).toBool());
            if(r->getExecute()){
                r->setExecutePath(settings.value("ExecutePath", "").toString());
                r->setExecuteArgs(settings.value("ExecuteArgs", "").toString());
            }
            r->setCheckMissed(settings.value("CheckMissed", false).toBool());
            QString state = settings.value("State", "Runned").toString();
            if(state == "Runned"){
                r->start();
                this->checkMissedReminder(r);
            }
            r->setLastCall(settings.value("LastCall").toDateTime());

            reminders.insert(r->getIndex(), r);
            settings.endGroup();
        }
    }
    settings.endGroup();
    this->loadRemindersList();
}

void MainWindow::saveSettings()
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    /* save reminders states */
    settings.beginGroup("Reminders");
    QMapIterator<int, Reminder*> i(reminders);
    while (i.hasNext()) {
       i.next();
       Reminder* r = i.value();
       settings.beginGroup(QString::number(r->getIndex()));
       QString state = "Stopped";
       if(r->getState() == Reminder::Runned || r->getState() == Reminder::Postponed){
           state = "Runned";
       }
       settings.setValue("State", state);
       settings.endGroup();
    }
    settings.endGroup();
    settings.beginGroup("Settings");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("splitterSizes", ui->splitter->saveState());
    settings.endGroup();
}

void MainWindow::writeToSettings(Reminder *r)
{
    //QDir appdir = qApp->applicationDirPath();
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Reminders");
        settings.remove(QString::number(r->getIndex()));
        settings.beginGroup(QString::number(r->getIndex()));
        settings.setValue("Name", r->getName());
        settings.setValue("Start", r->getStart());
        switch(r->getType()){
        case Reminder::Once: {
            settings.setValue("Type", "Once");
            settings.setValue("Autodelete", r->getAutodelete());
            break;
        }
        case Reminder::Minutely: {
            settings.setValue("Type", "Minutely");
            settings.setValue("Minutes", r->getMinutes());
            break;
        }
        case Reminder::Hourly: {
            settings.setValue("Type", "Hourly");
            settings.setValue("Hours", r->getHours());
            break;
        }
        case Reminder::Daily: {
            settings.setValue("Type", "Daily");
            settings.beginWriteArray("Days");
            bool* days = r->getDays();
            for(int n=0; n<7; n++){
                settings.setArrayIndex(n);
                settings.setValue("day", days[n]);
            }
            settings.endArray();
            break;
        }
        case Reminder::Monthly: {
            settings.setValue("Type", "Monthly");
            break;
        }
        case Reminder::MonthlyByDay: {
            settings.setValue("Type", "MonthlyByDay");
            break;
        }
        case Reminder::Yearly: {
            settings.setValue("Type", "Yearly");
            break;
        }
        case Reminder::YearlyByDay: {
            settings.setValue("Type", "YearlyByDay");
            break;
        }
        case Reminder::Timeout: {
            settings.setValue("Type", "Timeout");
            settings.setValue("Timeout", r->getTimeout());
            break;
        }
        default:
            break;
        }
        settings.setValue("Audio", r->hasAudio());
        if(r->hasAudio()){
            settings.setValue("AudioName", r->getAudioName());
        }
        settings.setValue("Tooltip", r->hasTooltip());
        if(r->hasTooltip()){
            settings.setValue("TooltipMessage", r->getTooltipMsg());
        }
        settings.setValue("Dialog", r->hasDialog());
        if(r->hasDialog()){
            settings.setValue("DialogMessage", r->getDialogMsg());
            settings.setValue("DialogAutoclose", r->hasAutoclose());
            if(r->hasAutoclose()){
                settings.setValue("DialogAutocloseInterval", r->getAutocloseInterval());
            }
        }
        settings.setValue("LoadUrl", r->hasUrl());
        if(r->hasUrl()){
            settings.setValue("Url", r->getUrl());
        }
        settings.setValue("Shutdown", r->getShutdown());
        if(r->getShutdown()){
            settings.setValue("ShutdownTimeout", r->getShutdownTimeout());
            switch(r->getShutdownType()){
            case Reminder::LogOff : settings.setValue("ShutdownType", "LogOff"); break;
            case Reminder::TurnOff : settings.setValue("ShutdownType", "TurnOff"); break;
            case Reminder::Restart : settings.setValue("ShutdownType", "Restart"); break;
            case Reminder::Hibernate : settings.setValue("ShutdownType", "Hibernate"); break;
            }
        }
        settings.setValue("Execute", r->getExecute());
        if(r->getExecute()){
            settings.setValue("ExecutePath", r->getExecutePath());
            settings.setValue("ExecuteArgs", r->getExecuteArgs());
        }
        settings.setValue("CheckMissed", r->hasCheckMissed());
        settings.endGroup();
    settings.endGroup();
}

void MainWindow::mute()
{
    if(media->state() != Phonon::StoppedState) media->stop();
    muteAction->setIcon(muteAction->isChecked() ? QIcon(":/Icons/icons/UnmuteReminder.png") : QIcon(":/Icons/icons/MuteReminder.png"));
    muteAction->setText(muteAction->isChecked() ? tr("Unmute") : tr("Mute"));
}

bool MainWindow::hasMuted()
{
    return muteAction->isChecked();
}

void MainWindow::deleteReminder()
{
    if(!current) return;
    else this->deleteReminder(current);
}

void MainWindow::deleteReminder(Reminder* r, bool ok)
{
    if(!r) return;
    if(!ok){
        int ret = QMessageBox::question(this, tr("Mind Reminder"),
                                        tr("Do you want to delete %1?").arg(current->getName()),
                                        QMessageBox::Ok | QMessageBox::Cancel);
        if(ret == QMessageBox::Cancel) return;
    }
    this->backupSettings();
    ReminderItem* i = r->getItem();
    if(model->removeRow(i->row())){
        reminders.remove(r->getIndex());
        //            remove from ini settings file ...
        QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
        QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
        //QDir appdir = qApp->applicationDirPath();
        QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
        settings.beginGroup("Reminders");
        settings.remove(QString::number(r->getIndex()));
        settings.endGroup();
        r->deleteLater();
    }
    if(!reminders.isEmpty()){
        QMap<int, Reminder*>::iterator i = reminders.begin();
        current = i.value();
        ui->listView->setCurrentIndex(current->getItem()->index());
    }
    else{
        current = 0;
    }
    this->reminderState(current);
}

void MainWindow::editSettings()
{
    ReminderSettings* dlg = new ReminderSettings(this);
    connect(dlg, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
    dlg->exec();
}

void MainWindow::exitApplication()
{
    qApp->quit();
}

void MainWindow::showTimeout()
{
    if(!current) return;
    int sdays = QDateTime::currentDateTime().secsTo(current->getNextRun());
    int days = sdays/86400;
    int shours = sdays%86400;
    int hours = shours/3600;
    int sminutes = shours%3600;
    int minutes = sminutes/60;
    int seconds = sminutes%60;
    QString nrun;
    if(days) nrun.append(QString("%1 %2 ")
            .arg(QString::number(days))
            .arg((days>1) ? tr("days") : tr("day")));
    if(hours) nrun.append(QString("%1 %2 ")
            .arg(QString::number(hours))
            .arg((hours>1) ? tr("hours") : tr("hour")));
    if(minutes) nrun.append(QString("%1 %2 ")
            .arg(QString::number(minutes))
            .arg((minutes>1) ? tr("minutes") : tr("minute")));
    if(seconds>0) nrun.append(QString("%1 %2 ")
            .arg(QString::number(seconds))
            .arg((seconds>1) ? tr("seconds") : tr("second")));

    ui->timeout_textLabel->setText(nrun);
}

void MainWindow::testReminder()
{
    if(!current) return;
    this->remind(current, true);
}

void MainWindow::executeLog(QProcess::ProcessState newState)
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QFile log(appdir.filePath("MindReminder.log"));
    QString msg = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss");
    switch(newState){
    case QProcess::NotRunning: msg.append(" - The process state is not running\n"); break;
    case QProcess::Starting: msg.append(" - The process state is started\n"); break;
    case QProcess::Running: msg.append(" - The process state is running\n"); break;
    }
    if (!log.open(QIODevice::WriteOnly | QIODevice::Append))
             return;
    QTextStream out(&log);
    out << msg;
}

void MainWindow::applySettings()
{
    ui->retranslateUi(this);
    ui->toolsNextrun_dateTimeEdit->setDisplayFormat(
                (qApp->property("use_secconds").toBool()) ?
                "dd.MM.yyyy HH:mm:ss" : "dd.MM.yyyy HH:mm"
                 );
    ui->last_dateTimeEdit->setDisplayFormat(
                (qApp->property("use_secconds").toBool()) ?
                "dd.MM.yyyy HH:mm:ss" : "dd.MM.yyyy HH:mm"
                 );
    if(dlg) dlg->applySettings();
}

void MainWindow::writeLastCall(Reminder *r, bool nulldate)
{
    r->setLastCall(nulldate ? QDateTime::QDateTime() : QDateTime::currentDateTime());
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Reminders");
        settings.beginGroup(QString::number(r->getIndex()));
        settings.setValue("LastCall", r->getLastCall());
        //settings.setValue("LastCall", QDateTime::fromString("10.01.2009 10:10:10", "dd.MM.yyyy hh:mm:ss"));
        settings.endGroup();
    settings.endGroup();
}

QDateTime MainWindow::getLastCall(Reminder *r) const
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Reminders");
        settings.beginGroup(QString::number(r->getIndex()));
            QDateTime last_call = settings.value("LastCall", 0).toDateTime();
            r->setLastCall(last_call);
        settings.endGroup();
    settings.endGroup();
    return last_call;
}

void MainWindow::checkMissedReminder(Reminder *r)
{
    if(!r->hasCheckMissed()){
        if(!qApp->property("check_missed").toBool()) return;
    }
    QString missed = r->missedReminders(this->getLastCall(r));
    if(!missed.isNull()){
        PostponeDialog* miss_dlg = new PostponeDialog(0);
        connect(miss_dlg, SIGNAL(clearHistory(int)), this, SLOT(clearReminderHistory(int)));
        miss_dlg->setWindowTitle(tr("%1 (missed events)").arg(r->getName()));
        miss_dlg->setDialogMsg(missed);
        miss_dlg->disablePostpone(true);
        miss_dlg->setReminderIndex(r->getIndex());
        miss_dlg->show();
        miss_dlg->activateWindow();
    }
}

void MainWindow::checkMissedReminders()
{
    QMapIterator<int, Reminder*> i(reminders);
    while (i.hasNext()) {
       i.next();
       Reminder* r = i.value();
        if(!r->hasCheckMissed()){
            if(!qApp->property("check_missed").toBool()) return;
        }
        QString missed = r->missedReminders(this->getLastCall(r));
        if(!missed.isNull()){
            PostponeDialog* miss_dlg = new PostponeDialog(0);
            miss_dlg->setWindowTitle(tr("%1 (missed events)").arg(r->getName()));
            miss_dlg->setDialogMsg(missed);
            miss_dlg->disablePostpone(true);
            miss_dlg->show();
            miss_dlg->activateWindow();
        }
    }
}

bool MainWindow::loadUpdatePlugin()
{
    QDir pluginsDir(qApp->applicationDirPath());
    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = pluginLoader.instance();
        if (plugin) {
            updmgr = qobject_cast<UpdMgrInterface *>(plugin);
            if (updmgr) return true;
        }
     }
     return false;
}

#ifdef Q_OS_WIN

bool MainWindow::winEvent(MSG *message, long *result)
{
    switch(message->message){
    case WM_POWERBROADCAST: {
        if(message->wParam == 4 && !reminders.isEmpty()){//windows system suspend

            QMapIterator<int, Reminder*> i(reminders);
            while (i.hasNext()) {
               i.next();
               Reminder* r = i.value();
               r->suspend();
               ReminderItem* ri = r->getItem();
               if(model->removeRow(ri->row())){
                   reminders.remove(r->getIndex());
                   r->deleteLater();
               }
            }
            current = 0;
        }
        if(message->wParam == 7){//resume windows system after suspend
            this->loadFromSettings();
        }
    }
    break;
    }
    return QMainWindow::winEvent(message, result);
}

#endif

void MainWindow::backupSettings()
{
    //qDebug() << "Perform settings backup...";
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    //QDir appdir = qApp->applicationDirPath();
    QFile* backup = new QFile(appdir.filePath("MindReminder.ini.bac"));
    if(backup->exists()){
        if(!backup->remove()){
            if(backup->error()!=0){
                delete backup;
                return;
            }
        }
    }
    QFile* settings = new QFile(appdir.filePath("MindReminder.ini"));
    if(!settings->copy(backup->fileName())){
        if(settings->error()!=0){
        }
    }
    delete backup;
    delete settings;
}

void MainWindow::clearReminderHistory(const int index)
{
    QSettings registry(QSettings::NativeFormat, QSettings::SystemScope, "Venelin Georgiev", "MindReminder");
    QDir appdir(registry.value("IniPath", QDir::homePath()).toString());
    QSettings settings(appdir.filePath("MindReminder.ini"), QSettings::IniFormat);
    settings.beginGroup("Reminders");
        settings.beginGroup(QString::number(index));
        settings.setValue("LastCall", QDateTime::currentDateTime());
        settings.endGroup();
    settings.endGroup();
}

void MainWindow::on_actionOrientation_triggered()
{
    ui->splitter->setOrientation(
                ui->splitter->orientation() == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal
                );
}
